package com.bsf.mvc.web;

import com.bsf.mvc.HttpContext;
import org.springframework.web.bind.WebDataBinder;

import java.beans.PropertyEditorSupport;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 自定义web数据绑定
 * 用于:mvc到Controller方法参数绑定改写
 * 1. 时间格式绑定兼容
 * 2. 允许参数为object类型的对象,public字段绑定（默认只绑定Property属性）
 */
public class CustomWebDataBinder {
    public void initBinder(WebDataBinder binder){
        //Date格式兼容
        binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) throws IllegalArgumentException {
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date date = null;
                try {
                    date = format.parse(text);
                } catch (ParseException e) {
                    format = new SimpleDateFormat("yyyy-MM-dd");
                    try {
                        date = format.parse(text);
                    } catch (ParseException e1) {
                        e1.printStackTrace();
                    }
                }
                setValue(date);
            }
        });
        if(binder.getTarget()!=null)
        {
            //允许public 字段注入（默认是属性）
            publicFiledDataBind(binder.getTarget(), binder);

        }
    }
    private void publicFiledDataBind(Object data,WebDataBinder binder)
    {
            if(data == null || data.getClass().isPrimitive() || isWrapClass(data.getClass()))
                return;
            Field[] publcfileds = data.getClass().getFields();
            if(publcfileds==null || publcfileds.length==0)
                return;
            for (Field f :publcfileds) {
                int modifier = f.getModifiers();
                if(Modifier.isFinal(modifier))
                    continue;
                //try to set public value to object
                String v = HttpContext.getRequest().getParameter(f.getName());
                if (v != null)
                {
                    try {
                        Object v2 = binder.getConversionService().convert(v,f.getType());
                        f.set(data, v2);
                    }
                    catch (Exception exp)
                    {}
                }
                //尝试深度遍历
                try {
                    Object propertyValue = f.get(data);
                    if (propertyValue!=null)
                        publicFiledDataBind(propertyValue,binder);
                }catch (Exception exp)
                {}
            }
    }

    private boolean isWrapClass(Class clz) {
        try {
            return ((Class) clz.getField("TYPE").get(null)).isPrimitive();
        } catch (Exception e) {
            return false;
        }
    }
}
